package com.scrm.server.wx.cp.service.impl;


import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.scrm.api.wx.cp.entity.*;
import com.scrm.api.wx.cp.enums.SopRuleWayEnum;
import com.scrm.api.wx.cp.enums.SopTermEnum;
import com.scrm.api.wx.cp.enums.WxMsgSendStatusEnum;
import com.scrm.common.constant.Constants;
import com.scrm.common.dto.BatchDTO;
import com.scrm.common.util.DateUtils;
import com.scrm.common.util.JwtUtil;
import com.scrm.common.util.ListUtils;
import com.scrm.server.wx.cp.dto.*;
import com.scrm.server.wx.cp.entity.*;
import com.scrm.server.wx.cp.service.*;
import com.scrm.server.wx.cp.utils.CronUtil;
import com.scrm.server.wx.cp.utils.WxMsgUtils;
import com.scrm.server.wx.cp.vo.*;
import lombok.extern.slf4j.Slf4j;
import com.scrm.server.wx.cp.mapper.BrGroupSopMapper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.scrm.api.wx.cp.dto.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.BeanUtils;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;

import java.text.SimpleDateFormat;
import java.util.*;

import com.scrm.common.util.UUID;
import com.scrm.common.exception.BaseException;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;

import java.util.stream.Collectors;

/**
 * 群sop 服务实现类
 * @author ouyang
 * @since 2022-04-17
 */
@Slf4j
@Service
@Transactional(rollbackFor = Exception.class)
public class BrGroupSopServiceImpl extends ServiceImpl<BrGroupSopMapper, BrGroupSop> implements IBrGroupSopService {

    @Autowired
    private IBrGroupSopRuleService groupSopRuleService;

    @Autowired
    private IXxlJobService xxlJobService;

    @Autowired
    private IStaffService staffService;

    @Autowired
    private IWxGroupChatService groupChatService;

    @Autowired
    private IWxGroupChatTagService groupChatTagService;

    @Autowired
    private IDepartmentService departmentService;

    @Autowired
    private IBrGroupSopDetailService detailService;

    @Autowired
    private IBrSopService sopService;

    @Autowired
    private IBrTodoService todoService;

    @Autowired
    private IWxTempFileService fileService;

    @Override
    public IPage<BrGroupSopVO> pageList(BrGroupSopPageDTO dto){
        LambdaQueryWrapper<BrGroupSop> wrapper = new QueryWrapper<BrGroupSop>()
        .lambda().eq(BrGroupSop::getExtCorpId, dto.getExtCorpId())
                .like(StringUtils.isNotBlank(dto.getName()), BrGroupSop::getName, dto.getName())
                .orderByDesc(BrGroupSop::getCreatedAt);
        IPage<BrGroupSop> page = page(new Page<>(dto.getPageNum(), dto.getPageSize()),wrapper);
        return page.convert(this::translation);
    }


    @Override
    public List<BrGroupSop> queryList(BrGroupSopQueryDTO dto){
        LambdaQueryWrapper<BrGroupSop> wrapper = new QueryWrapper<BrGroupSop>()
        .lambda().eq(BrGroupSop::getExtCorpId, dto.getExtCorpId()).eq(BrGroupSop::getStatus, dto.getStatus())
                .eq(BrGroupSop::getTerm, dto.getTerm());
        return Optional.ofNullable(list(wrapper)).orElse(new ArrayList<>());
    }


    @Override
    public BrGroupSopVO findById(String id){
        return translation(checkExists(id));
    }


    @Override
    public BrGroupSop save(BrGroupSopSaveDTO dto){

        //封装数据
        BrGroupSop brGroupSop = new BrGroupSop();
        BeanUtils.copyProperties(dto,brGroupSop);

        checkData(brGroupSop);
        brGroupSop.setId(UUID.get32UUID())
                .setUpdatedAt(new Date())
                .setCreatedAt(new Date())
                .setStatus(BrGroupSop.ENABLE_STATUS)
                .setCreator(JwtUtil.getUserId());

        if (ListUtils.isNotEmpty(dto.getDepartmentIds())){
            brGroupSop.setDepartmentIds(dto.getDepartmentIds().stream().map(Long::parseLong).collect(Collectors.toList()));
        }
        //入库
        save(brGroupSop);

        //规则处理
        handleRule(brGroupSop,dto.getRuleList());
        return brGroupSop;
    }


    @Override
    public BrGroupSop update(BrGroupSopUpdateDTO dto){

        //校验参数
        BrGroupSop old = checkExists(dto.getId());

        //封装数据
        BrGroupSop brGroupSop = new BrGroupSop();
        BeanUtils.copyProperties(dto, brGroupSop);
        checkData(brGroupSop);
        brGroupSop.setCreatedAt(old.getCreatedAt())
                .setCreator(old.getCreator())
                .setUpdatedAt(new Date())
                .setEditor(JwtUtil.getUserId());

        if (ListUtils.isNotEmpty(dto.getDepartmentIds())){
            brGroupSop.setDepartmentIds(dto.getDepartmentIds().stream().map(Long::parseLong).collect(Collectors.toList()));
        }

        //入库
        updateById(brGroupSop);

        //更新规则数据
        handleRule(brGroupSop,dto.getRuleList());

        return brGroupSop;
    }


    @Override
    public void delete(String id){

        //校验参数
        BrGroupSop brGroupSop = checkExists(id);

        //删除
        removeById(id);

        //删除sop规则
        groupSopRuleService.deleteBySopId(id);

    }


    @Override
    public void batchDelete(BatchDTO<String> dto){

        //校验参数
        List<BrGroupSop> brSopList = new ArrayList<>();
        Optional.ofNullable(dto.getIds()).orElse(new ArrayList<>()).forEach(id -> brSopList.add(checkExists(id)));

        List<String> ruleIdList = groupSopRuleService.list(new LambdaQueryWrapper<BrGroupSopRule>().in(BrGroupSopRule::getSopId, dto.getIds()))
                .stream().map(BrGroupSopRule::getId).collect(Collectors.toList());
        if(ListUtils.isNotEmpty(ruleIdList)){
            groupSopRuleService.batchDelete(new BatchDTO<String>().setIds(ruleIdList));
        }

        //删除
        removeByIds(dto.getIds());
    }


    /**
     * 数据检查
     * @param brGroupSop  brGroupSop
     */
    private void checkData(BrGroupSop brGroupSop) {
        if (count(new LambdaQueryWrapper<BrGroupSop>()
                .eq(BrGroupSop::getExtCorpId, brGroupSop.getExtCorpId())
                .ne(brGroupSop.getId() != null, BrGroupSop::getId, brGroupSop.getId())
                .eq(BrGroupSop::getName,brGroupSop.getName()))>0){
            throw new BaseException("sop名称已存在，请重新命名！");
        }
        //校验触发条件
        if (SopTermEnum.getNameByCode(brGroupSop.getTerm()) == null) {
            throw new BaseException("该触发条件不存在!");
        }

    }

    private void handleRule(BrGroupSop brGroupSop,List<BrGroupSopRuleSaveOrUpdateDTO> ruleList) {
        //查询选择的群聊信息
        WxGroupChatQueryDTO dto = new WxGroupChatQueryDTO();
        BeanUtils.copyProperties(brGroupSop,dto);
        List<WxGroupChat> wxGroupChats = groupChatService.queryList(dto);

        //移除已被删除的规则
        List<String> ruleIds = ruleList.stream().map(e -> e.getId()).collect(Collectors.toList());
        List<String> needDeleteRuleIds = Optional.ofNullable(groupSopRuleService.list(new LambdaQueryWrapper<BrGroupSopRule>()
                .select(BrGroupSopRule::getId)
                .eq(BrGroupSopRule::getSopId, brGroupSop.getId())
                .notIn(ListUtils.isNotEmpty(ruleIds), BrGroupSopRule::getId, ruleIds)
        )).orElse(new ArrayList<>()).stream().map(BrGroupSopRule::getId).collect(Collectors.toList());

        if (ListUtils.isNotEmpty(needDeleteRuleIds)) {
            groupSopRuleService.batchDelete(new BatchDTO<String>().setIds(needDeleteRuleIds));
        }
        for (BrGroupSopRuleSaveOrUpdateDTO rule : ruleList) {
            //校验规则参数
            if (StringUtils.isBlank(rule.getName())) {
                throw new BaseException("规则名称不能为空");
            }
            Integer way = rule.getWay();
            if (way == null || SopRuleWayEnum.getNameByCode(way) == null) {
                throw new BaseException("执行方式不存在");
            }
            BrGroupSopRule groupSopRule;
            //新增或更新规则表
            if (StringUtils.isNotBlank(rule.getId())){
                rule.setExtCorpId(brGroupSop.getExtCorpId()).setEditor(brGroupSop.getEditor());
                groupSopRule = groupSopRuleService.update(rule);
                //删除定时任务
                List<Integer> jobIds = rule.getJobId();
                if (ListUtils.isNotEmpty(jobIds)){
                    jobIds.forEach(jobId->{
                        xxlJobService.delete(jobId);
                    });
                }

            }else {
                rule.setExtCorpId(brGroupSop.getExtCorpId()).setSopId(brGroupSop.getId()).setCreator(brGroupSop.getCreator());
                groupSopRule = groupSopRuleService.save(rule);
            }
            // 查询群聊为空，无需处理
            if (ListUtils.isEmpty(wxGroupChats)){
                return;
            }

            //存放生成定时任务id集合
            List<Integer> jobIdList = new ArrayList<>();

            BrSopRuleParamDto paramDto = new BrSopRuleParamDto();
            BeanUtils.copyProperties(groupSopRule,paramDto);
            paramDto.setSopName(brGroupSop.getName());

            //触发条件为创建群聊
            if (SopTermEnum.CREATE_GROUP.getCode().equals(brGroupSop.getTerm())){
                Map<String,Date> executeTimeMap = new HashMap<>();
                List<WxGroupChat> needChatList = new ArrayList<>();
                //计算创建群聊时间是否需添加定时任务
                for (WxGroupChat wxGroupChat : wxGroupChats) {
                    Date executeTime = DateUtils.getDate(wxGroupChat.getCreateTime(), rule.getStartDay(), rule.getStartTime());
                    if (DateUtils.belongCalendarBefore(executeTime)){
                        String extId = wxGroupChat.getExtChatId();
                        needChatList.add(wxGroupChat);
                        executeTimeMap.put(extId,executeTime);
                    }
                }

                if (ListUtils.isEmpty(needChatList)){
                    continue;
                }

                //创建定时群发任务<执行时间+员工id,群聊id集合>
                Map<String, List<String>> sendIdMap = needChatList.stream().map(e -> {
                    BrGroupSopDetail detail = new BrGroupSopDetail();
                    detail.setExtChatId(e.getExtChatId()).setExtStaffId(e.getOwner()
                    ).setExecuteAt(executeTimeMap.get(e.getExtChatId()));
                    return detail;
                }).collect(Collectors.groupingBy(i -> DateUtils.dateToStr(i.getExecuteAt()) + "_" + i.getExtStaffId(),
                        Collectors.mapping(BrGroupSopDetail::getExtChatId, Collectors.toList())));

                //<执行时间,<员工id，群聊id集合>>
                Map<String, Map<String,List<String>>> map = new HashMap<>();
                sendIdMap.forEach((k,chatIds)->{
                            String[] split = k.split("_");
                            String executeTime = split[0];
                            String staffId = split[1];
                            if (!map.containsKey(executeTime)){
                                Map<String,List<String>> staffChatMap = new HashMap<>();
                                staffChatMap.put(staffId,chatIds);
                                map.put(executeTime,staffChatMap);
                            }else {
                                Map<String, List<String>> oldMap = map.get(executeTime);
                                oldMap.put(staffId,chatIds);
                                map.put(executeTime,oldMap);
                            }
                        }
                );

                map.forEach((executetime,idMap)->{
                            jobIdList.add(sopService.createXxlJob(idMap,DateUtils.strToDate(executetime),paramDto,Constants.SEND_MSG_HANDLER,false,BrSopMsgTaskDto.GROUP_SOP_TYPE));
                        }
                );
            }else if (SopTermEnum.TIME.getCode().equals(brGroupSop.getTerm())){
                //触发条件为时间
                //<员工id,群聊id集合>
                Map<String, List<String>> sendIdList = wxGroupChats.stream().collect(Collectors.groupingBy(WxGroupChat::getOwner,
                        Collectors.mapping(WxGroupChat::getExtChatId, Collectors.toList())));

                if (DateUtils.belongCalendarBefore(rule.getExecuteAt())) {
                    jobIdList.add(sopService.createXxlJob(sendIdList, rule.getExecuteAt(),paramDto,Constants.SEND_MSG_HANDLER,false,BrSopMsgTaskDto.GROUP_SOP_TYPE));
                }

                if (!CronUtil.PERIOD_NEVER.equals(rule.getPeriod())){
                    //生成周期定时任务,在执行时间当天执行
                    Integer periodJobId = sopService.createXxlJob(sendIdList, rule.getExecuteAt(), paramDto, Constants.CREATE_JOB_HANDLER,false,BrSopMsgTaskDto.GROUP_SOP_TYPE);
                    jobIdList.add(periodJobId);

                    //生成停止周期的任务，在结束重复时间当天执行
                    Integer stopJobId = sopService.createStopJob(DateUtils.handle(rule.getExecuteAt(),rule.getEndAt()),groupSopRule.getId(), rule.getName(),groupSopRule.getCreator(),BrSopMsgTaskDto.GROUP_SOP_TYPE);
                    jobIdList.add(stopJobId);
                }
            }
            //sop为启用状态，启用定时任务
            if (BrSop.ENABLE_STATUS.equals(brGroupSop.getStatus())){
                jobIdList.forEach(jobId->xxlJobService.start(jobId));
            }
            groupSopRuleService.update(new UpdateWrapper<BrGroupSopRule>().lambda()
                    .eq(BrGroupSopRule::getId,groupSopRule.getId())
                    .set(BrGroupSopRule::getJobId,jobIdList.toString()));

        }



    }

    /**
     * 翻译
     * @param brGroupSop 实体
     * @return BrGroupSopVO 结果集
     * @author ouyang
     * @date 2022-04-17
     */
    private BrGroupSopVO translation(BrGroupSop brGroupSop){
        BrGroupSopVO vo = new BrGroupSopVO();
        BeanUtils.copyProperties(brGroupSop, vo);

        //翻译创建者
        Staff staff = staffService.find(brGroupSop.getCreator());
        vo.setCreatorCN(staff!=null?staff.getName():brGroupSop.getCreator());

        //查询规则
        vo.setRuleList(groupSopRuleService.queryList(new BrGroupSopRuleQueryDTO()
                .setExtCorpId(brGroupSop.getExtCorpId()).setSopId(brGroupSop.getId())));

        //翻译选择的群聊集合
        if (ListUtils.isNotEmpty(brGroupSop.getGroupIds())){
            vo.setGroupChatList(groupChatService.list(new LambdaQueryWrapper<WxGroupChat>()
                    .eq(WxGroupChat::getExtCorpId, brGroupSop.getExtCorpId())
                    .in(WxGroupChat::getExtChatId, brGroupSop.getGroupIds())));
        }
        //翻译群标签
        if (ListUtils.isNotEmpty(brGroupSop.getGroupTags())){
            vo.setTagList(groupChatTagService.list(new LambdaQueryWrapper<WxGroupChatTag>()
                    .eq(WxGroupChatTag::getExtCorpId, brGroupSop.getExtCorpId())
                    .in(WxGroupChatTag::getId, brGroupSop.getGroupTags())));
        }
        //翻译群主，选择的部门
        if (ListUtils.isNotEmpty(brGroupSop.getDepartmentIds())){
            vo.setDepartmentList(departmentService.list(new LambdaQueryWrapper<Department>()
                    .eq(Department::getExtCorpId, brGroupSop.getExtCorpId())
                    .in(Department::getExtId, brGroupSop.getDepartmentIds())));

        }

        //翻译群主,选择的员工
        if (ListUtils.isNotEmpty(brGroupSop.getLeaderIds())){
            vo.setStaffList(staffService.list(new LambdaQueryWrapper<Staff>()
                    .eq(Staff::getExtCorpId, brGroupSop.getExtCorpId())
                    .in(Staff::getExtId, brGroupSop.getLeaderIds())));
        }

        return vo;
    }


    @Override
    public BrGroupSop checkExists(String id){
        if (StringUtils.isBlank(id)) {
            return null;
        }
        BrGroupSop byId = getById(id);
        if (byId == null) {
            throw new BaseException("群sop不存在");
        }
        return byId;
    }

    @Override
    public void updateStatus(BrSopUpdateStatusDTO dto) {
        BrGroupSop brGroupSop = checkExists(dto.getId());
        brGroupSop.setStatus(dto.getStatus()).setUpdatedAt(new Date()).setEditor(JwtUtil.getUserId());
        updateById(brGroupSop);

        //对定时任务禁用/启用
        List<BrGroupSopRule> ruleList = groupSopRuleService.list(new LambdaQueryWrapper<BrGroupSopRule>().eq(BrGroupSopRule::getSopId, dto.getId()));
        List<Integer> jobIds = new ArrayList<>();
        if (!SopTermEnum.TIME.getCode().equals(brGroupSop.getTerm())) {
            ruleList.stream().forEach(e -> {
                if (ListUtils.isNotEmpty(e.getJobId())) {
                    jobIds.addAll(e.getJobId());
                }
            });
        } else {
            ruleList.stream().forEach(e -> {
                if (ListUtils.isNotEmpty(e.getJobId())) {
                    if (!CronUtil.PERIOD_NEVER.equals(e.getPeriod())) {
                        if (DateUtils.belongCalendarBefore(DateUtils.handle(e.getExecuteAt(), e.getEndAt()))) {
                            jobIds.addAll(e.getJobId());
                        }
                    } else if (DateUtils.belongCalendarBefore(e.getExecuteAt())) {
                        jobIds.addAll(e.getJobId());
                    }
                }
            });
        }
        if (ListUtils.isEmpty(jobIds)){
            return;
        }
        //启用
        if (BrGroupSop.ENABLE_STATUS.equals(dto.getStatus())){
            for (Integer jobId : jobIds) {
                xxlJobService.start(jobId);
            }

        }else if (BrGroupSop.DISABLE_STATUS.equals(dto.getStatus())){
            //禁用
            for (Integer jobId : jobIds) {
                xxlJobService.stop(jobId);
            }
        }
    }

    @Override
    public BrGroupSopPushDetailVO getPushDetail(String ruleId, String executeAt, String staffId,Integer jobId, String extCorpId) {
        List<BrGroupSopDetail> list = detailService.list(new LambdaQueryWrapper<BrGroupSopDetail>()
                .eq(BrGroupSopDetail::getExtCorpId, extCorpId)
                .eq(BrGroupSopDetail::getExtStaffId, staffId)
                .eq(BrGroupSopDetail::getRuleId, ruleId)
                .eq(BrGroupSopDetail::getJobId, jobId)
                .eq(BrGroupSopDetail::getExecuteAt, executeAt));

        List<String> chatIds = Optional.ofNullable(list).orElse(new ArrayList<>()).stream().map(BrGroupSopDetail::getExtChatId).collect(Collectors.toList());
        List<WxGroupChat> chatList = new ArrayList<>();
        if (ListUtils.isNotEmpty(chatIds)){
            chatList = groupChatService.list(new QueryWrapper<WxGroupChat>().lambda()
                    .eq(WxGroupChat::getExtCorpId, extCorpId)
                    .in(WxGroupChat::getExtChatId, chatIds));
        }

        BrGroupSopPushDetailVO result = new BrGroupSopPushDetailVO();
        BrGroupSopDetail brGroupSopDetail = list.get(0);

        //翻译文件
        List<WxMsgAttachmentDTO> mediaList = brGroupSopDetail.getMsg().getMedia();
        if (ListUtils.isNotEmpty(mediaList)) {
            mediaList.stream().filter(e -> e.getFile() != null
                    && StringUtils.isNotBlank(e.getFile().getId()))
                    .forEach(e -> e.setFile(fileService.checkExists(e.getFile().getId())));
        }

        result.setMsg(brGroupSopDetail.getMsg()).setSopName(brGroupSopDetail.getSopName()).setChatList(chatList).setWay(brGroupSopDetail.getWay())
                .setSendStatus(brGroupSopDetail.getSendStatus());

        BrTodo brTodo = todoService.getOne(new BrTodoQueryDTO().setExtCorpId(extCorpId).setBusinessId(ruleId)
                .setBusinessId1(String.valueOf(jobId)).setType(BrTodo.GROUP_SOP_TYPE)
                .setOwnerExtId(staffId).setCreateTime(executeAt));

        result.setTodoStatus(brTodo.getStatus());
        result.setTodoDeadlineTime(brTodo.getDeadlineTime());

        return result;
    }

    @Override
    public void createTaskForAddGroupChat(WxGroupChat groupChat) {
        //查询是否存在创建群聊触发的sop
        List<BrGroupSop> groupSopList = queryList(new BrGroupSopQueryDTO().setExtCorpId(groupChat.getExtCorpId()).setStatus(BrGroupSop.ENABLE_STATUS).setTerm(SopTermEnum.CREATE_GROUP.getCode()));
        if (ListUtils.isEmpty(groupSopList)) {
            return;
        }
        //查询sop下的规则
        List<BrGroupSopRule> ruleList = groupSopRuleService.list(new LambdaQueryWrapper<BrGroupSopRule>().eq(BrGroupSopRule::getExtCorpId, groupChat.getExtCorpId())
                .in(BrGroupSopRule::getSopId, groupSopList.stream().map(e -> e.getId()).collect(Collectors.toList())));

        for (BrGroupSopRule rule : ruleList) {
            Date executeTime = DateUtils.getDate(groupChat.getCreateTime(), rule.getStartDay(), rule.getStartTime());
            if (DateUtils.belongCalendarBefore(executeTime)){
                //原有的定时任务id集合
                List<Integer> ruleJobIds = rule.getJobId();
                XxlJobQueryDto dto = new XxlJobQueryDto();
                dto.setIds(ruleJobIds).setTriggerStatus(XxlJobQueryDto.STATUS_ENABLE).setScheduleConf(DateUtils.getCron(executeTime));
                List<XxlJobInfo> list = xxlJobService.getList(dto);
                if (ListUtils.isEmpty(list)) {
                    //原本没有定时任务，生成
                    BrSopRuleParamDto paramDto = new BrSopRuleParamDto();
                    BeanUtils.copyProperties(rule,paramDto);
                    BrGroupSop brSop = getById(rule.getSopId());
                    paramDto.setSopName(brSop!=null?brSop.getName():"");
                    Map<String,List<String>> idMap = new HashMap<>();
                    idMap.put(groupChat.getOwner(), Arrays.asList(groupChat.getExtChatId()));
                    Integer jobId = sopService.createXxlJob(idMap, executeTime, paramDto,Constants.SEND_MSG_HANDLER,false,BrSopMsgTaskDto.GROUP_SOP_TYPE);
                    //启用任务
                    xxlJobService.start(jobId);
                    List<Integer> jobIdList = Optional.ofNullable(rule.getJobId()).orElse(new ArrayList<>());
                    jobIdList.add(jobId);
                    //更新jobId字段
                    groupSopRuleService.update(new UpdateWrapper<BrGroupSopRule>().lambda()
                            .eq(BrGroupSopRule::getId,rule.getId())
                            .set(BrGroupSopRule::getJobId,jobIdList.toString()));
                }else {
                    //原本有定时任务，更新该定时任务参数
                    XxlJobInfo xxlJobInfo = list.get(0);
                    BrSopMsgTaskDto brSopMsgTaskDto = JSON.parseObject(xxlJobInfo.getExecutorParam(), BrSopMsgTaskDto.class);
                    Map<String, List<String>> idMap = brSopMsgTaskDto.getIdMap();
                    String staffId = groupChat.getOwner();
                    if (idMap.containsKey(staffId)){
                        List<String> listByStaff = idMap.get(staffId);
                        listByStaff.add(groupChat.getExtChatId());
                        idMap.put(staffId,listByStaff.stream().distinct().collect(Collectors.toList()));
                    }else {
                        idMap.put(staffId, Arrays.asList(groupChat.getExtChatId()));
                    }
                    brSopMsgTaskDto.setIdMap(idMap);
                    xxlJobInfo.setExecutorParam(JSON.toJSONString(brSopMsgTaskDto));
                    xxlJobService.update(xxlJobInfo);
                }
            }
        }
    }
    @Override
    public List<BrGroupSopRuleDetailVO> getExecuteDetail(String sopId) {
        List<BrGroupSopRuleDetailVO> result =  new ArrayList<>();
        List<BrGroupSopRule> list = groupSopRuleService.list(new LambdaQueryWrapper<BrGroupSopRule>()
                .eq(BrGroupSopRule::getSopId, sopId).orderByAsc(BrGroupSopRule::getCreatedAt));

        for (BrGroupSopRule sopRule : list) {
            List<BrGroupSopDetail> detailList = detailService.list(new LambdaQueryWrapper<BrGroupSopDetail>()
                    .eq(BrGroupSopDetail::getRuleId, sopRule.getId()));

            BrGroupSopRuleDetailVO vo = new BrGroupSopRuleDetailVO();
            BeanUtils.copyProperties(sopRule,vo);
            vo.setRuleName(sopRule.getName());
            List<BrGroupSopRuleExecuteVO> executeVOS = new ArrayList<>();
            //根据执行时间分组
            Map<Date, List<BrGroupSopDetail>> listByTime = detailList.stream().collect(Collectors.groupingBy(BrGroupSopDetail::getExecuteAt));
            listByTime.forEach((executeTime,sopDetailList)->{
                BrGroupSopRuleExecuteVO executeVO = new BrGroupSopRuleExecuteVO();
                executeVO.setExecuteAt(executeTime);
                executeVO.setChatNum(sopDetailList.size());

                //根据群主分组
                Map<String, List<BrGroupSopDetail>> listByStaff = sopDetailList.stream().collect(Collectors.groupingBy(BrGroupSopDetail::getExtStaffId));
                Set<String> staffSet = listByStaff.keySet();

                //已完成推送群主数量
                executeVO.setDoneNum(staffSet.size());

                List<BrGroupSopExecuteDetailVO> executeDetailList = new ArrayList<>();
                for (String staffId : staffSet) {
                    BrGroupSopExecuteDetailVO detailVO = new BrGroupSopExecuteDetailVO();

                    //没有该员工，直接返回extId
                    detailVO.setStaff(staffService.find(sopRule.getExtCorpId(),staffId));
                    List<BrGroupSopDetail> details = listByStaff.get(staffId);

                    BrGroupSopDetail detail = details.get(0);
                    detailVO.setChatNum(details.size());
                    detailVO.setSendStatus(detail.getSendStatus());
                    detailVO.setSendTime(detail.getSendTime());

                    //查询待办状态
                    BrTodo brTodo = todoService.getOne(new BrTodoQueryDTO().setExtCorpId(detail.getExtCorpId()).setBusinessId(sopRule.getId())
                            .setBusinessId1(String.valueOf(detail.getJobId())).setType(BrTodo.GROUP_SOP_TYPE)
                            .setOwnerExtId(staffId).setCreateTime(DateUtils.dateToStr(executeTime)));

                    detailVO.setTodoStatus(brTodo.getStatus());
                    detailVO.setTodoDeadlineTime(brTodo.getDeadlineTime());

                    executeDetailList.add(detailVO);
                }
                executeVO.setExecuteDetailList(executeDetailList);
                //未完成发送群主数量
                executeVO.setNotDoneNum((int) executeDetailList.stream().filter(e-> !WxMsgSendStatusEnum.STATUS_SEND.getCode().equals(e.getSendStatus())).count());
                executeVOS.add(executeVO);
            });
            Collections.sort(executeVOS, Comparator.comparing(BrGroupSopRuleExecuteVO::getExecuteAt,Comparator.reverseOrder()));
            vo.setExecuteDetailList(executeVOS);
            result.add(vo);
        }
        return result;
    }

    @Override
    public void updateSendStatus(BrSopUpdateSendStatusDTO dto) {
        detailService.update(new LambdaUpdateWrapper<BrGroupSopDetail>()
                .eq(BrGroupSopDetail::getExtStaffId, dto.getStaffId())
                .eq(BrGroupSopDetail::getRuleId, dto.getRuleId())
                .eq(BrGroupSopDetail::getJobId, dto.getJobId())
                .eq(BrGroupSopDetail::getExecuteAt, dto.getExecuteAt())
                .set(BrGroupSopDetail::getSendStatus, dto.getSendStatus())
                .set(BrGroupSopDetail::getSendTime, new Date())
            );

        todoService.update(new LambdaUpdateWrapper<BrTodo>()
                .eq(BrTodo::getOwnerExtId, dto.getStaffId())
                .eq(BrTodo::getBusinessId, dto.getRuleId())
                .eq(BrTodo::getBusinessId1, dto.getJobId())
                .eq(BrTodo::getCreateTime, dto.getExecuteAt())
                .set(BrTodo::getStatus,BrTodo.DONE_STATUS)
        );

    }

    @Override
    public void remind(BrSopRemindDTO dto) {
        List<BrGroupSopDetail> details = detailService.list(new LambdaQueryWrapper<BrGroupSopDetail>()
                .eq(BrGroupSopDetail::getExtCorpId, dto.getExtCorpId())
                .eq(BrGroupSopDetail::getExtStaffId, dto.getStaffId())
                .eq(BrGroupSopDetail::getRuleId, dto.getRuleId())
                .eq(BrGroupSopDetail::getExecuteAt, dto.getExecuteAt()));

        String REMAIN_TIPS = "【任务提醒】您有任务还未完成！\n" +
                "\n" +
                "任务名称：%s\n" +
                "\n" +
                "创建时间：%s\n" +
                "\n" +
                "可在历史信息中查询详情，记得及时完成哦";

        String content = String.format(REMAIN_TIPS,details.get(0).getSopName(),
                new SimpleDateFormat("YYYY-MM-dd HH:mm").format(dto.getExecuteAt()));
        WxMsgUtils.sendMessage(dto.getExtCorpId(),content, Arrays.asList(dto.getStaffId()));

    }

    @Override
    public Integer countChat(WxGroupChatQueryDTO dto) {
        return groupChatService.queryList(dto).size();
    }
}
